package com.turing.model.caller.handler;


import com.turing.common.annotations.RLockAnnotation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@Aspect
@Slf4j
@Component
public class RLockAnnotationHandler {

    @Autowired
    private RedissonClient redissonClient;

    @Pointcut("@annotation(com.turing.common.annotations.RLockAnnotation)")
    public void methodAspect(){};

    @Around("methodAspect()")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {

        Class<?> targetClass = joinPoint.getTarget().getClass();
        Signature signature = joinPoint.getSignature();
        MethodSignature ms = (MethodSignature) signature;
        Method targetMethod = targetClass.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
        RLockAnnotation annotation = targetMethod.getAnnotation(RLockAnnotation.class);
        String lockKey = annotation.lockKey();
        RLock rLock = redissonClient.getLock(lockKey);
        if ( rLock == null || rLock.isLocked() ) {
            return null;
        }
        boolean locked = false;
        try{
            locked = rLock.tryLock(1, TimeUnit.MINUTES);
           if(!locked){
               //log.info("<<<<<<<<<<<<<<<<<<<<<<<< failed to get distribute lock,lock key is:"+lockKey);
              return null;
          }else{
              //log.info("<<<<<<<<<<<<<<<<<<<<<<<< successful getting distribute lock,lock key is:"+lockKey);
              Object[] args = joinPoint.getArgs();
              return joinPoint.proceed(args);
          }
       }catch(Exception e){
           e.printStackTrace();
       }finally{
            if(rLock.isLocked()){
                //log.info("<<<<<<<<<<<<<<<<<<<<<<<< releasing distribute lock,lock key is:"+lockKey);
                rLock.unlock();
            }
       }
        return null;
    }
}